package com.shujia.scala

object Demo11Fun {
  def main(args: Array[String]): Unit = {
    /**
     * 面向对象编程 - 将对象传来传去
     * 1、以对象作为参数
     * 2、以对象作为返回值
     * 需要明确参数的类型，返回值的类型和对象的类型   - 可以使用多态（父类的引用指向子类的对象）
     *
     * 面向函数编程-- 将函数传来传去  - 高阶函数
     * 1、以函数作为参数  （必须要很熟练）
     * 2、以函数作为返回值 （了解）
     * 需要明确函数的类型
     *
     * 函数的类型-- 由函数参数类型和返回值类型决定
     * strToInt是一个参数为String返回值为Int类型的函数
     *
     * 函数类型的表示  ：String => Int， 前面是参数类型，后面是返回值类型
     *
     */

    def strToInt(str: String): Int = {
      str.toInt
    }

    val i: Int = strToInt("100")
    println(i)

    //scala中函数也是一个对象，可以改变引用
    val strToIntTemp: String => Int = strToInt

    val j = strToIntTemp("200")
    println(j)


    /**
     * 1、函数作为参数
     *
     * fun的参数是一个函数（是一个参数为String返回值Int类型的函数）
     *
     * 以函数作为参数编程的作用--- 我们可以将一个代码逻辑中需要变化的部分抽象出来，让调用者以函数的形式传递进来
     *
     */


    //定义一个参数为函数的函数
    def fun(f: String => Int): Unit = {
      println("执行fun")
      //调用传进来的函数
      println("调用f")
      val i = f("1000")
      println("打印i")
      println(i)
    }


    //f1是一个参数为String返回值为Int类型的函数
    def f1(s: String): Int = {
      println("执行f1")
      s.toInt
    }

    println("==" * 100)
    //调用fun需要传入一个参数为String返回值为Int类型的函数
    println("调用fun")
    fun(f1)

    println("==" * 100)

    def f2(s: String): Int = {
      println("执行f2")
      s.toInt + 200
    }

    //可以多次调用传入不同的函数
    fun(f2)
    println("==" * 100)


    /**
     * lambda表达式（匿名函数：没有名字的函数）
     * (s: String) => s.toInt
     * 前面是参数，后面是函数体和返回值，默认最后一行作为返回值
     *
     * lambda表达式返回值的类型会自动推断
     *
     */

    //使用lambda表达式定义函数
    val f3 = (s: String) => s.toInt
    //fun(f3)

    //使用lambda表达式作为函数的参数
    fun((s: String) => {
      s.toInt
    })

    //函数提只有一行可以省略括号
    fun((s: String) => s.toInt)

    //lambda表达式的参数类型可以自动推断
    fun(f => f.toInt)

    //如果参数只使用了一次可以使用下划线代替
    fun(_.toInt)

  }

}
